// $ANTLR 2.7.6 (2005-12-22): "resources/grammars/OperationLabelParser.g" -> "OperationLabelParser.java"$

package com.cea.papyrus.classdiagram.parsers.antlr;

import org.eclipse.uml2.uml.*;
import java.util.Iterator;
import java.util.Collection;
import java.util.Vector;

import com.cea.papyrus.classdiagram.parsers.util.Assert;

import com.cea.papyrus.umlutils.Parameter;

import antlr.TokenBuffer;
import antlr.TokenStreamException;
import antlr.TokenStreamIOException;
import antlr.ANTLRException;
import antlr.LLkParser;
import antlr.Token;
import antlr.TokenStream;
import antlr.RecognitionException;
import antlr.NoViableAltException;
import antlr.MismatchedTokenException;
import antlr.SemanticException;
import antlr.ParserSharedInputState;
import antlr.collections.impl.BitSet;

public class OperationLabelParser extends antlr.LLkParser       implements OperationLabelParserTokenTypes
 {

	public OperationLabelParser(TokenStream lexer, Operation operation) {
		this(lexer);
		this.operation = operation;	
		this.contextPackage = new com.cea.papyrus.umlutils.Package(operation.getClass_().getPackage());
	}
	
	/**
	 * Validation state (true = validation : does not modify the operation
	 */
	private boolean isValidation = false;
	
	/**
	 * @return the isValidation boolean
	 */
	public boolean isValidation() {
		return isValidation;
	}

	/**
	 * @param isValidation the isValidation to set (true -> do not modify the operation)
	 */
	public void setValidation(boolean isValidation) {
		this.isValidation = isValidation;
	}
	
	/**
	 * Modified Operation 
	 */
	private Operation operation;
	
	/**
	 * @return the operation
	 */
	public Operation getOperation() {
		return operation;
	}

	/**
	 * @param operation the operation to set
	 */
	public void setOperation(Operation operation) {
		this.operation = operation;
	}
    	
    /** debug mode */
    protected final boolean debugMode = false;  	
    	
    /**
     * Debug method (~System.out.println)
     */
    private void debug(Object debug) {
    	if(debugMode) {
    		System.out.println(debug);	
    	}	
    }
    
    /**
     * Error method (~System.err.println)
     */
    private void error(Object debug) {
    	if(debugMode) {
    		System.err.println(debug);	
    	}	
    }
    
    // all possible modified elements on operation (with default values : necessary ?!)
  	private String name;
    private VisibilityKind visibility;
    private org.eclipse.uml2.uml.Parameter returnParameter;
    private Collection<org.eclipse.uml2.uml.Parameter> parameters = new Vector<org.eclipse.uml2.uml.Parameter>();
    private Collection<org.eclipse.uml2.uml.Operation> redefinedOperations = new Vector<org.eclipse.uml2.uml.Operation>();
    private boolean isQuery = false;
    private boolean isUnique;
    private Collection<org.eclipse.uml2.uml.Constraint> constraints = new Vector<org.eclipse.uml2.uml.Constraint>();
    
    private com.cea.papyrus.umlutils.Package contextPackage = null;
    
	/**
	 * Apply values to the operation. <BR> 
	 * Modifications can not be applied directly. The parser must wait the end, 
	 * until it reaches the end of the label. If the end is reached without any error,
	 * new values can be applied to the target operation.
	 */
	@SuppressWarnings("unchecked")
	private void applyValues() {
		if(!isValidation){
			debug("\nvalues applied :");
			debug("+ name: "+name);
			debug("+ visibility: "+visibility);
			
			debug("+ parameters: "+parameters);
			debug("+ returnParameter: "+returnParameter);
			
			debug("+ isQuery: "+isQuery);
			debug("+ redefinedOperations: "+redefinedOperations);
			
			// setting values
			operation.setName(name);
			operation.setVisibility(visibility);
			
			// parameters = cllection of parameters AND return parameter, if exists
			operation.getOwnedParameters().clear();
			operation.getOwnedParameters().addAll(parameters);
			if(returnParameter != null) {
				operation.getOwnedParameters().add(returnParameter);
			}
			
			// is the operation a Query ?
			operation.setIsQuery(isQuery);
			
			// operation redefinition
			operation.getRedefinedOperations().clear();
			operation.getRedefinedOperations().addAll(redefinedOperations);
			
		} 
	}
	
	/**
	 * Find a type given its name and a context to find it.
	 * @param name the name of the type
	 * @return the type found or <code>null</code> if the element was not found.
	 */
	private Type findTypeByName(String name, org.eclipse.uml2.uml.Element context) throws RecognitionException {
		Type type = null;
		int numTypes = 0;
		org.eclipse.uml2.uml.Package contextPackage = context.getNearestPackage();
		
		// seek the package in which the element should be found...
		Iterator it = contextPackage.getMembers().iterator();
		while( it.hasNext() ) {
			Object tmp = it.next();
			if( tmp instanceof Type ) {
				Type element = ( Type )tmp;
				if(  element.getName().equals(name)  ) {
					numTypes++;
					type = element;
				}
			}
		}
		if(type == null) {// type not found in default package. search in imports.
			it = contextPackage.getImportedMembers().iterator();
			while( it.hasNext() ) {
				Object tmp = it.next();
				if( tmp instanceof Type ) {
					Type element = ( Type )tmp;
					if(  element.getName().equals(name)  ) {
						type = element;
						numTypes++;
					}
				}
			}
		}
		
		if(numTypes == 0) {
			throw new RecognitionException("Type "+name+" not found for operation "+operation.getName());
		} else if(numTypes > 1) {
			debug("There are "+numTypes+" types with the same name....");
		}
		
		return type;
	}

protected OperationLabelParser(TokenBuffer tokenBuf, int k) {
  super(tokenBuf,k);
  tokenNames = _tokenNames;
}

public OperationLabelParser(TokenBuffer tokenBuf) {
  this(tokenBuf,2);
}

protected OperationLabelParser(TokenStream lexer, int k) {
  super(lexer,k);
  tokenNames = _tokenNames;
}

public OperationLabelParser(TokenStream lexer) {
  this(lexer,2);
}

public OperationLabelParser(ParserSharedInputState state) {
  super(state,2);
  tokenNames = _tokenNames;
}

	public final void label() throws RecognitionException, TokenStreamException {
		
		
		visibility();
		name();
		parameterList();
		
				applyValues();
			
	}
	
	public final void visibility() throws RecognitionException, TokenStreamException {
		
		
		{
		switch ( LA(1)) {
		case PLUS:
		{
			match(PLUS);
			visibility = VisibilityKind.PUBLIC_LITERAL;
			break;
		}
		case MINUS:
		{
			match(MINUS);
			visibility = VisibilityKind.PRIVATE_LITERAL;
			break;
		}
		case SHARP:
		{
			match(SHARP);
			visibility = VisibilityKind.PROTECTED_LITERAL;
			break;
		}
		case TILDE:
		{
			match(TILDE);
			visibility = VisibilityKind.PACKAGE_LITERAL;
			break;
		}
		case IDENTIFIER:
		{
			visibility = VisibilityKind.PUBLIC_LITERAL; /*default visibility = public */
			break;
		}
		default:
		{
			throw new NoViableAltException(LT(1), getFilename());
		}
		}
		}
	}
	
	public final void name() throws RecognitionException, TokenStreamException {
		
		Token  id = null;
		
		id = LT(1);
		match(IDENTIFIER);
		
				name = id.getText();
			
	}
	
	public final void parameterList() throws RecognitionException, TokenStreamException {
		
		
		match(LPAREN);
		{
		switch ( LA(1)) {
		case IDENTIFIER:
		case LITERAL_in:
		case LITERAL_out:
		case LITERAL_inout:
		{
			parameter();
			{
			_loop8:
			do {
				if ((LA(1)==COMMA)) {
					match(COMMA);
					parameter();
				}
				else {
					break _loop8;
				}
				
			} while (true);
			}
			break;
		}
		case RPAREN:
		{
			break;
		}
		default:
		{
			throw new NoViableAltException(LT(1), getFilename());
		}
		}
		}
		match(RPAREN);
	}
	
	public final void parameter() throws RecognitionException, TokenStreamException {
		
		
				
				// create a new Parameter
				com.cea.papyrus.umlutils.Parameter currentParameter = new com.cea.papyrus.umlutils.Parameter(UMLFactory.eINSTANCE.createParameter());
			
		{
		switch ( LA(1)) {
		case LITERAL_in:
		case LITERAL_out:
		case LITERAL_inout:
		{
			direction(currentParameter);
			break;
		}
		case IDENTIFIER:
		{
			break;
		}
		default:
		{
			throw new NoViableAltException(LT(1), getFilename());
		}
		}
		}
		parameterName(currentParameter);
		match(COLON);
		parameterType(currentParameter);
		{
		switch ( LA(1)) {
		case LSQUARE:
		{
			multiplicity(currentParameter);
			break;
		}
		case COMMA:
		case RPAREN:
		{
			break;
		}
		default:
		{
			throw new NoViableAltException(LT(1), getFilename());
		}
		}
		}
		
				parameters.add(currentParameter.getUml2Parameter());
			
	}
	
	public final void direction(
		 com.cea.papyrus.umlutils.Parameter parameter 
	) throws RecognitionException, TokenStreamException {
		
		
		
				Assert.isNotNull(parameter);
			
		{
		switch ( LA(1)) {
		case LITERAL_in:
		{
			match(LITERAL_in);
			parameter.getUml2Parameter().setDirection(ParameterDirectionKind.IN_LITERAL);
			break;
		}
		case LITERAL_out:
		{
			match(LITERAL_out);
			parameter.getUml2Parameter().setDirection(ParameterDirectionKind.OUT_LITERAL);
			break;
		}
		case LITERAL_inout:
		{
			match(LITERAL_inout);
			parameter.getUml2Parameter().setDirection(ParameterDirectionKind.INOUT_LITERAL);
			break;
		}
		default:
		{
			throw new NoViableAltException(LT(1), getFilename());
		}
		}
		}
	}
	
	public final void parameterName(
		 com.cea.papyrus.umlutils.Parameter parameter 
	) throws RecognitionException, TokenStreamException {
		
		Token  id = null;
		
		
				Assert.isNotNull(parameter);
			
		id = LT(1);
		match(IDENTIFIER);
		
				parameter.getUml2Parameter().setName(id.getText());
			
	}
	
	public final void parameterType(
		 com.cea.papyrus.umlutils.Parameter parameter 
	) throws RecognitionException, TokenStreamException {
		
		Token  id = null;
		
		switch ( LA(1)) {
		case IDENTIFIER:
		{
			
					Assert.isNotNull(parameter);
				
			{
			id = LT(1);
			match(IDENTIFIER);
			
						// find Type by name
						com.cea.papyrus.umlutils.Type type = contextPackage.findTypeByName(id.getText());
						if(type != null) {
							parameter.getUml2Parameter().setType(type.getUml2Type());
						}
						else {
							throw new RecognitionException("type "+id.getText()+" not found in package "+contextPackage.getName());
						}
					
			}
			break;
		}
		case LT:
		{
			{
			match(LT);
			match(LITERAL_Undefined);
			match(GT);
			}
			break;
		}
		default:
		{
			throw new NoViableAltException(LT(1), getFilename());
		}
		}
	}
	
	public final void multiplicity(
		 com.cea.papyrus.umlutils.Parameter parameter 
	) throws RecognitionException, TokenStreamException {
		
		
		
				Assert.isNotNull(parameter);
				int lower = 0;
				int upper = 0;
			
		match(LSQUARE);
		{
		if ((LA(1)==INTEGER) && (LA(2)==POINT_POINT)) {
			lower=lowerMultiplicity();
			match(POINT_POINT);
			upper=upperMultiplicity();
			
						if(lower > upper && upper != -1) {
							throw new RecognitionException("Lower bound ("+lower+") is greater than upper bound ("+upper+")");
						}
						parameter.getUml2Parameter().setLower(lower);
						parameter.getUml2Parameter().setUpper(upper);
					
		}
		else if ((LA(1)==INTEGER||LA(1)==STAR) && (LA(2)==RSQUARE)) {
			upper=upperMultiplicity();
			
						if(upper == -1) {
							parameter.getUml2Parameter().setLower(0);
							parameter.getUml2Parameter().setUpper(upper);
						} else {
							parameter.getUml2Parameter().setLower(upper);
							parameter.getUml2Parameter().setUpper(upper);
						}
					
		}
		else {
			throw new NoViableAltException(LT(1), getFilename());
		}
		
		}
		match(RSQUARE);
	}
	
	public final int  lowerMultiplicity() throws RecognitionException, TokenStreamException {
		int lower = 0;
		
		Token  in = null;
		
		in = LT(1);
		match(INTEGER);
		
				lower = Integer.parseInt(in.getText());
			
		return lower;
	}
	
	public final int  upperMultiplicity() throws RecognitionException, TokenStreamException {
		int upper = 0;
		
		
		upper=unlimitedNatural();
		return upper;
	}
	
	public final int  unlimitedNatural() throws RecognitionException, TokenStreamException {
		int value = 0 ;
		
		Token  in = null;
		
		{
		switch ( LA(1)) {
		case STAR:
		{
			match(STAR);
			value = -1;
			break;
		}
		case INTEGER:
		{
			in = LT(1);
			match(INTEGER);
			value = Integer.parseInt(in.getText());
			break;
		}
		default:
		{
			throw new NoViableAltException(LT(1), getFilename());
		}
		}
		}
		return value;
	}
	
	
	public static final String[] _tokenNames = {
		"<0>",
		"EOF",
		"<2>",
		"NULL_TREE_LOOKAHEAD",
		"PLUS",
		"MINUS",
		"SHARP",
		"TILDE",
		"IDENTIFIER",
		"LPAREN",
		"COMMA",
		"RPAREN",
		"COLON",
		"\"in\"",
		"\"out\"",
		"\"inout\"",
		"LT",
		"\"Undefined\"",
		"GT",
		"LSQUARE",
		"POINT_POINT",
		"RSQUARE",
		"INTEGER",
		"STAR",
		"NL",
		"WS",
		"QUESTION_MARK",
		"LNOT",
		"DOUBLE_QUOTE",
		"SINGLE_QUOTE",
		"LCURLY",
		"DOUBLE_LCURLY",
		"RCURLY",
		"DOUBLE_RCURLY",
		"LOGICAL_AND",
		"DOUBLE_LOGICAL_AND",
		"PIPE",
		"DOUBLE_PIPE",
		"POINT",
		"SEMI",
		"DOUBLE_COLON",
		"RULE_ASSIGN",
		"ARROW",
		"DIV",
		"EQ",
		"ISEQ",
		"ISNE",
		"DOUBLE_LT",
		"LE",
		"DOUBLE_GT",
		"GE",
		"INCR",
		"DECR",
		"CALLOPERATION",
		"DIGIT",
		"ALPHA",
		"UNDERSCORE",
		"REAL",
		"REAL_OR_INT"
	};
	
	
	}
